<?php

use nsCms\Jwt;

//缓存
function saveCache($name = '', $id = '')
{
    if ($name == 'Field') {
        if ($id) {
            $Model = db($name);
            $data = $Model->order('sort')->where('moduleid=' . $id)->column('*', 'field');
            $name = $id . '_' . $name;
            $data = $data ? $data : null;
            cache($name, $data);
        } else {
            $module = cache('Module');
            foreach ($module as $key => $val) {
                saveCache($name, $key);
            }
        }
    } elseif ($name == 'System') {
        $info = db('config')->where('type', 'site')->where('status', 1)->select();
        $info = convert_arr_kv($info, 'name', 'value');
        cache($name, $info);
    } elseif ($name == 'Module') {
        $Model = db($name);
        $list = $Model->order('sort')->select();
        $pkid = $Model->getPk();
        $data = [];
        $smalldata = [];
        foreach ($list as $key => $val) {
            $data [$val [$pkid]] = $val;
            $smalldata[$val['name']] = $val [$pkid];
        }
        cache($name, $data);
        cache('Mod', $smalldata);
    } elseif ($name == 'cm') {
        $list = db('category')
            ->alias('c')
            ->join('module m', 'c.moduleid = m.id')
            ->order('c.sort')
            ->field('c.*,m.title as mtitle,m.name as mname')
            ->select();
        cache($name, $list);
    } else {
        $Model = db($name);
        $list = $Model->order('sort')->select();
        $pkid = $Model->getPk();
        $data = [];
        foreach ($list as $key => $val) {
            $data [$val [$pkid]] = $val;
        }
        cache($name, $data);
    }
    return true;
}

//样式解析
function style($title_style)
{
    $title_style = explode(';', $title_style);
    return $title_style[0] . ';' . $title_style[1];
}

//请求返回
function callback($status = 0, $msg = '', $url = null, $data = '')
{
    $data = [
        'msg'    => $msg,
        'url'    => $url,
        'data'   => $data,
        'status' => $status,
    ];
    return $data;
}

//验证
function getvalidate($info)
{
    $validate_data = [];
    if ($info['minlength']) $validate_data['minlength'] = ' minlength:' . $info['minlength'];
    if ($info['maxlength']) $validate_data['maxlength'] = ' maxlength:' . $info['maxlength'];
    if ($info['required']) $validate_data['required'] = ' required:true';
    if ($info['pattern']) $validate_data['pattern'] = ' ' . $info['pattern'] . ':true';
    $errormsg = '';
    if ($info['errormsg']) {
        $errormsg = ' title="' . $info['errormsg'] . '"';
    }
    $validate = implode(',', $validate_data);
    $validate = 'validate="' . $validate . '" ';
    $parseStr = $validate . $errormsg;
    return $parseStr;
}


function string2array($info)
{
    if ($info == '') return [];
    $r = '';
    eval("\$r = $info;");
    return $r;
}

function array2string($info)
{
    if ($info == '') return '';
    if (!is_array($info)) {
        $string = stripslashes($info);
    }
    foreach ($info as $key => $val) {
        $string[$key] = stripslashes($val);
    }
    $setup = var_export($string, true);
    return $setup;
}

//初始表单
function getForm($form, $info, $value = '')
{
    $type = $info['type'];
    return $form->$type($info, $value);
}

//文件单位换算
function byte_format($input, $dec = 0)
{
    $prefix_arr = ["B", "KB", "MB", "GB", "TB"];
    $value = round($input, $dec);
    $i = 0;
    while ($value > 1024) {
        $value /= 1024;
        $i++;
    }
    $return_str = round($value, $dec) . $prefix_arr[$i];
    return $return_str;
}

//时间日期转换
function toDate($time, $format = 'Y-m-d H:i:s')
{
    if (empty ($time)) {
        return '';
    }
    $format = str_replace('#', ':', $format);
    return date($format, $time);
}

//模板文件
function template_file($module = '')
{
    $viewPath = config('template.view_path');
    $viewSuffix = config('template.view_suffix');
    $viewPath = $viewPath ? $viewPath : 'view';
    $filepath = think\facade\Env::get('app_path') . strtolower(config('default_module')) . '/' . $viewPath . '/';
    $temp_files = dir_list($filepath, $viewSuffix);
    $arr = [];
    foreach ($temp_files as $key => $file) {
        $dirname = basename($file);
        if ($module) {
            if (strstr($dirname, $module . '_')) {
                $arr[$key]['value'] = substr($dirname, 0, strrpos($dirname, '.'));
                $arr[$key]['filename'] = $dirname;
                $arr[$key]['filepath'] = $file;
            }
        } else {
            $arr[$key]['value'] = substr($dirname, 0, strrpos($dirname, '.'));
            $arr[$key]['filename'] = $dirname;
            $arr[$key]['filepath'] = $file;
        }
    }
    return $arr;
}

//列目录
function dir_list($path, $exts = '', $list = [])
{
    $path = dir_path($path);
    $files = glob($path . '*');
    foreach ($files as $v) {
        $fileext = fileext($v);
        if (!$exts || preg_match("/\.($exts)/i", $v)) {
            $list[] = $v;
            if (is_dir($v)) {
                $list = dir_list($v, $exts, $list);
            }
        }
    }
    return $list;
}

//列文件
function dir_path($path)
{
    $path = str_replace('\\', '/', $path);
    if (substr($path, -1) != '/') $path = $path . '/';
    return $path;
}

function fileext($filename)
{
    return strtolower(trim(substr(strrchr($filename, '.'), 1, 10)));
}

//检查字段
function checkField($table, $value, $field)
{
    $count = db($table)->where([$field => $value])->count();
    if ($count > 0) {
        return true;
    } else {
        return false;
    }
}

//随机字符串
function rand_string($len = 6, $type = '', $addChars = '')
{
    $str = '';
    switch ($type) {
        case 0:
            $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars;
            break;
        case 1:
            $chars = str_repeat('0123456789', 3);
            break;
        case 2:
            $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars;
            break;
        case 3:
            $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars;
            break;
        case 4:
            $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借" . $addChars;
            break;
        default :
            // 默认去掉了容易混淆的字符oOLl和数字01，要添加请使用addChars参数
            $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars;
            break;
    }
    if ($len > 10) {//位数过长重复字符串一定次数
        $chars = $type == 1 ? str_repeat($chars, $len) : str_repeat($chars, 5);
    }
    if ($type != 4) {
        $chars = str_shuffle($chars);
        $str = substr($chars, 0, $len);
    } else {
        // 中文随机字
        for ($i = 0; $i < $len; $i++) {
            $str .= msubstr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1);
        }
    }
    return $str;
}

/**
 * 验证输入的邮件地址是否合法
 */
function is_email($user_email)
{
    $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
    if (strpos($user_email, '@') !== false && strpos($user_email, '.') !== false) {
        if (preg_match($chars, $user_email)) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * 验证输入的手机号码是否合法
 */
function is_mobile_phone($mobile_phone)
{
    $chars = "/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$|17[0-9]{1}[0-9]{8}$/";
    if (preg_match($chars, $mobile_phone)) {
        return true;
    }
    return false;
}

//获取ip
function getIp()
{
    if (@$_SERVER['HTTP_CLIENT_IP'] && $_SERVER['HTTP_CLIENT_IP'] != 'unknown') {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (@$_SERVER['HTTP_X_FORWARDED_FOR'] && $_SERVER['HTTP_X_FORWARDED_FOR'] != 'unknown' && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return preg_match('/^\d[\d.]+\d$/', $ip) ? $ip : '';
}

//字符串截取
function str_cut($sourcestr, $cutlength, $suffix = '...')
{
    $returnstr = '';
    $i = 0;
    $n = 0;
    $str_length = strlen($sourcestr);//字符串的字节数
    while (($n < $cutlength) and ($i <= $str_length)) {
        $temp_str = substr($sourcestr, $i, 1);
        $ascnum = Ord($temp_str);//得到字符串中第$i位字符的ascii码
        if ($ascnum >= 224)    //如果ASCII位高与224，
        {
            $returnstr = $returnstr . substr($sourcestr, $i, 3); //根据UTF-8编码规范，将3个连续的字符计为单个字符
            $i = $i + 3;            //实际Byte计为3
            $n++;            //字串长度计1
        } elseif ($ascnum >= 192) //如果ASCII位高与192，
        {
            $returnstr = $returnstr . substr($sourcestr, $i, 2); //根据UTF-8编码规范，将2个连续的字符计为单个字符
            $i = $i + 2;            //实际Byte计为2
            $n++;            //字串长度计1
        } elseif ($ascnum >= 65 && $ascnum <= 90) //如果是大写字母，
        {
            $returnstr = $returnstr . substr($sourcestr, $i, 1);
            $i = $i + 1;            //实际的Byte数仍计1个
            $n++;            //但考虑整体美观，大写字母计成一个高位字符
        } else                //其他情况下，包括小写字母和半角标点符号，
        {
            $returnstr = $returnstr . substr($sourcestr, $i, 1);
            $i = $i + 1;            //实际的Byte数计1个
            $n = $n + 0.5;        //小写字母和半角标点等与半个高位字符宽...
        }
    }
    if ($n > $cutlength) {
        $returnstr = $returnstr . $suffix;//超过长度时在尾处加上省略号
    }
    return $returnstr;
}

//删除目录及文件
function dir_delete($dir)
{
    $dir = dir_path($dir);
    if (!is_dir($dir)) return false;
    $list = glob($dir . '*');
    foreach ($list as $v) {
        is_dir($v) ? dir_delete($v) : @unlink($v);
    }
    return @rmdir($dir);
}

/**
 * CURL请求
 *
 * @param $url 请求url地址
 * @param $method 请求方法 get post
 * @param null $postfields post数据数组
 * @param array $headers 请求header信息
 * @param bool|false $debug 调试开启 默认false
 * @return mixed
 */
function httpRequest($url, $method, $postfields = null, $headers = [], $debug = false)
{
    $method = strtoupper($method);
    $ci = curl_init();
    /* Curl settings */
    curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
    curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间，如果设置为0，则无限等待 */
    curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
    curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
    switch ($method) {
        case "POST":
            curl_setopt($ci, CURLOPT_POST, true);
            if (!empty($postfields)) {
                $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
                curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
            }
            break;
        default:
            curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
            break;
    }
    $ssl = preg_match('/^https:\/\//i', $url) ? true : false;
    curl_setopt($ci, CURLOPT_URL, $url);
    if ($ssl) {
        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, false); // https请求 不验证证书和hosts
        curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, false); // 不从证书中检查SSL加密算法是否存在
    }
    //curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
    //curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量，这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
    curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ci, CURLINFO_HEADER_OUT, true);
    /*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
    $response = curl_exec($ci);
    $requestinfo = curl_getinfo($ci);
    $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
    if ($debug) {
        echo "=====post data======\r\n";
        var_dump($postfields);
        echo "=====info===== \r\n";
        print_r($requestinfo);
        echo "=====response=====\r\n";
        print_r($response);
    }
    curl_close($ci);
    return $response;
}

/**
 * @param $arr
 * @param $key_name
 * @return array
 * 将数据库中查出的列表以指定的 id 作为数组的键名
 */
function convert_arr_key($arr, $key_name)
{
    $arr2 = [];
    foreach ($arr as $key => $val) {
        $arr2[$val[$key_name]] = $val;
    }
    return $arr2;
}

//判断图片的类型从而设置图片路径
function imgUrl($img, $defaul = '')
{
    if ($img) {
        if (substr($img, 0, 4) == 'http') {
            $imgUrl = $img;
        } else {
            $imgUrl = $img;
        }
    } else {
        if ($defaul) {
            $imgUrl = $defaul;
        } else {
            $imgUrl = '/static/admin/images/thumb.png';
        }
        
    }
    return $imgUrl;
}

//格式化字节
function format_bytes($size, $delimiter = '')
{
    $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
    return round($size, 2) . $delimiter . $units[$i];
}

//判断设备
function isMobile()
{
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
        return true;
    
    // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
    if (isset ($_SERVER['HTTP_VIA'])) {
        // 找不到为flase,否则为true
        return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
    }
    // 脑残法，判断手机发送的客户端标志,兼容性有待提高
    if (isset ($_SERVER['HTTP_USER_AGENT'])) {
        $clientkeywords = ['nokia', 'sony', 'ericsson', 'mot', 'samsung', 'htc', 'sgh', 'lg', 'sharp', 'sie-', 'philips', 'panasonic', 'alcatel', 'lenovo', 'iphone', 'ipod', 'blackberry', 'meizu', 'android', 'netfront', 'symbian', 'ucweb', 'windowsce', 'palm', 'operamini', 'operamobi', 'openwave', 'nexusone', 'cldc', 'midp', 'wap', 'mobile'];
        // 从HTTP_USER_AGENT中查找手机浏览器的关键字
        if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT'])))
            return true;
    }
    // 协议法，因为有可能不准确，放到最后判断
    if (isset ($_SERVER['HTTP_ACCEPT'])) {
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
            return true;
        }
    }
    return false;
}

/**
 * 过滤数组元素前后空格 (支持多维数组)
 *
 * @param $array 要过滤的数组
 * @return array|string
 */
function trim_array_element($array)
{
    if (!is_array($array))
        return trim($array);
    return array_map('trim_array_element', $array);
}

/**
 * @param $arr
 * @param $key_name
 * @return array
 * 将数据库中查出的列表以指定的 值作为数组的键名，并以另一个值作为键值
 */
function convert_arr_kv($arr, $key_name, $value)
{
    $arr2 = [];
    foreach ($arr as $key => $val) {
        $arr2[$val[$key_name]] = $val[$value];
    }
    return $arr2;
}

/**
 * 邮件发送
 *
 * @param $to    接收人
 * @param string $subject 邮件标题
 * @param string $content 邮件内容(html模板渲染后的内容)
 * @throws Exception
 * @throws phpmailerException
 */
function send_email($to, $subject = '', $content = '')
{
    $mail = new PHPMailer\PHPMailer\PHPMailer();
    $arr = db('config')->where('inc_type', 'smtp')->select();
    $config = convert_arr_kv($arr, 'name', 'value');
    
    $mail->CharSet = 'UTF-8'; //设定邮件编码，默认ISO-8859-1，如果发中文此项必须设置，否则乱码
    $mail->isSMTP();
    $mail->SMTPDebug = 0;
    //调试输出格式
    //$mail->Debugoutput = 'html';
    //smtp服务器
    $mail->Host = $config['smtp_server'];
    //端口 - likely to be 25, 465 or 587
    $mail->Port = $config['smtp_port'];
    
    if ($mail->Port == '465') {
        $mail->SMTPSecure = 'ssl';
    }// 使用安全协议
    //Whether to use SMTP authentication
    $mail->SMTPAuth = true;
    //发送邮箱
    $mail->Username = $config['smtp_user'];
    //密码
    $mail->Password = $config['smtp_pwd'];
    //Set who the message is to be sent from
    $mail->setFrom($config['smtp_user'], $config['email_id']);
    //回复地址
    //$mail->addReplyTo('replyto@example.com', 'First Last');
    //接收邮件方
    if (is_array($to)) {
        foreach ($to as $v) {
            $mail->addAddress($v);
        }
    } else {
        $mail->addAddress($to);
    }
    
    $mail->isHTML(true);// send as HTML
    //标题
    $mail->Subject = $subject;
    //HTML内容转换
    $mail->msgHTML($content);
    return $mail->send();
}

function safe_html($html)
{
    $elements = [
        'html'       => [],
        'body'       => [],
        'a'          => ['target', 'href', 'title', 'class', 'style'],
        'abbr'       => ['title', 'class', 'style'],
        'address'    => ['class', 'style'],
        'area'       => ['shape', 'coords', 'href', 'alt'],
        'article'    => [],
        'aside'      => [],
        'audio'      => ['autoplay', 'controls', 'loop', 'preload', 'src', 'class', 'style'],
        'b'          => ['class', 'style'],
        'bdi'        => ['dir'],
        'bdo'        => ['dir'],
        'big'        => [],
        'blockquote' => ['cite', 'class', 'style'],
        'br'         => [],
        'caption'    => ['class', 'style'],
        'center'     => [],
        'cite'       => [],
        'code'       => ['class', 'style'],
        'col'        => ['align', 'valign', 'span', 'width', 'class', 'style'],
        'colgroup'   => ['align', 'valign', 'span', 'width', 'class', 'style'],
        'dd'         => ['class', 'style'],
        'del'        => ['datetime'],
        'details'    => ['open'],
        'div'        => ['class', 'style'],
        'dl'         => ['class', 'style'],
        'dt'         => ['class', 'style'],
        'em'         => ['class', 'style'],
        'font'       => ['color', 'size', 'face'],
        'footer'     => [],
        'h1'         => ['class', 'style'],
        'h2'         => ['class', 'style'],
        'h3'         => ['class', 'style'],
        'h4'         => ['class', 'style'],
        'h5'         => ['class', 'style'],
        'h6'         => ['class', 'style'],
        'header'     => [],
        'hr'         => [],
        'i'          => ['class', 'style'],
        'img'        => ['src', 'alt', 'title', 'width', 'height', 'id', 'class'],
        'ins'        => ['datetime'],
        'li'         => ['class', 'style'],
        'mark'       => [],
        'nav'        => [],
        'ol'         => ['class', 'style'],
        'p'          => ['class', 'style'],
        'pre'        => ['class', 'style'],
        's'          => [],
        'section'    => [],
        'small'      => [],
        'span'       => ['class', 'style'],
        'sub'        => ['class', 'style'],
        'sup'        => ['class', 'style'],
        'strong'     => ['class', 'style'],
        'table'      => ['width', 'border', 'align', 'valign', 'class', 'style'],
        'tbody'      => ['align', 'valign', 'class', 'style'],
        'td'         => ['width', 'rowspan', 'colspan', 'align', 'valign', 'class', 'style'],
        'tfoot'      => ['align', 'valign', 'class', 'style'],
        'th'         => ['width', 'rowspan', 'colspan', 'align', 'valign', 'class', 'style'],
        'thead'      => ['align', 'valign', 'class', 'style'],
        'tr'         => ['rowspan', 'align', 'valign', 'class', 'style'],
        'tt'         => [],
        'u'          => [],
        'ul'         => ['class', 'style'],
        'video'      => ['autoplay', 'controls', 'loop', 'preload', 'src', 'height', 'width', 'class', 'style'],
        'embed'      => ['src', 'height', 'align', 'width', 'class', 'style', 'type', 'pluginspage', 'wmode', 'play', 'loop', 'menu', 'allowscriptaccess', 'allowfullscreen'],
        'source'     => ['src', 'type'],
    ];
    $html = strip_tags($html, '<' . implode('><', array_keys($elements)) . '>');
    $xml = new \DOMDocument();
    libxml_use_internal_errors(true);
    if (!strlen($html)) {
        return '';
    }
    if ($xml->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $html)) {
        foreach ($xml->getElementsByTagName("*") as $element) {
            if (!isset($elements[$element->tagName])) {
                $element->parentNode->removeChild($element);
            } else {
                for ($k = $element->attributes->length - 1; $k >= 0; --$k) {
                    if (!in_array($element->attributes->item($k)->nodeName, $elements[$element->tagName])) {
                        $element->removeAttributeNode($element->attributes->item($k));
                    } elseif (in_array($element->attributes->item($k)->nodeName, ['href', 'src', 'style', 'background', 'size'])) {
                        $_keywords = ['javascript:', 'javascript.:', 'vbscript:', 'vbscript.:', ':expression'];
                        $find = false;
                        foreach ($_keywords as $a => $b) {
                            if (false !== strpos(strtolower($element->attributes->item($k)->nodeValue), $b)) {
                                $find = true;
                            }
                        }
                        if ($find) {
                            $element->removeAttributeNode($element->attributes->item($k));
                        }
                    }
                }
            }
        }
    }
    $html = substr($xml->saveHTML($xml->documentElement), 12, -14);
    $html = strip_tags($html, '<' . implode('><', array_keys($elements)) . '>');
    return $html;
}


//生成token
function getJwtToken($userId, $openid)
{
    $key = config('app.jwt.key');
    $jwtData = [
        'lat'    => config('app.jwt.lat'),
        'nbf'    => config('app.jwt.nbf'),
        'exp'    => config('app.jwt.exp'),
        'uid'    => $userId,
        'openid' => $openid,
    ];
    $jwtToken = JWT::encode($jwtData, $key);
    return $jwtToken;
}

//验证token
function checkJwtToken($token)
{
    try {
        $key = config('app.jwt.key');
        $info = JWT::decode($token, $key, ['HS256']);
        return (array)$info;
    } catch (Exception $ex) {
        return ['uid' => 0, 'openid' => 0, 'msg' => $ex->getMessage()];
    }
}

/*
*ajax返回的统一标准数组
*@param array $data
*@param string $info
*@return array
*/
function outJson($code = 1, $msg = '操作成功', $data = '', $total = 0, $httpCode = 200)
{
    $r_data = [];
    $r_data['code'] = $code;
    $r_data['msg'] = $msg;
    $r_data['data'] = (empty($data) && !is_array($data)) ? '' : $data;
    $r_data['total'] = $total;
    return json($r_data, $httpCode);
}

//检测密码 长度至少8位，必须包含数字+大写+小写三种！
function checkPassword($password)
{
    if (preg_match('/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?!.*\s).{8,}/', $password)) {
        return true;
    } else {
        return false;
    }
}

//发送短信
function sms_send($code, $mobile)
{
    $time = 10;
    $text = "【牛皮世家】您的验证码是" . $code . "。有效期" . $time . "分钟，如非本人操作，请忽略本短信";
    $param = [
        'apikey' => '1078bdd86163c800b1c332d7e2d88190',
        'mobile' => $mobile,
        'text'   => $text,
    ];
    $rs = json_decode(httpRequest("https://sms.yunpian.com/v2/sms/single_send.json", 'post', $param), true);
    return $rs;
}

//base64上传
function upload_base64($data, $filepath)
{
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $data, $result)) {
        $type = $result[2];
        $filename = uniqid() . $type;
        if (file_put_contents($filepath . $filename, base64_decode(str_replace($result[1], '', $data)))) {
            return $filepath . $filename;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

//判断字段存在并不为空
function isset_full($arr, $key)
{
    if (isset($arr[$key]) && !empty($arr[$key])) {
        return true;
    } else {
        return false;
    }
}

//分页
function getPage()
{
    $page = input('page/i', 10);
    $limit = input('limit/i', 10);
    return ['list_rows' => $limit, 'page' => $page];
}

function post($url, $param = [])
{
    var_dump(http_build_query($param));
    if (!is_array($param)) {
        throw new Exception("参数必须为array");
    }
    $httph = curl_init($url);
    curl_setopt($httph, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($httph, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($httph, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($httph, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
    curl_setopt($httph, CURLOPT_POST, 1);//设置为POST方式
    //curl_setopt($httph, CURLOPT_POSTFIELDS, $param);//多维数组
    curl_setopt($httph, CURLOPT_POSTFIELDS, http_build_query($param));//多维数组
    curl_setopt($httph, CURLOPT_RETURNTRANSFER, 1);
    //curl_setopt($httph, CURLOPT_HEADER,1);
    $rst = curl_exec($httph);
    $errorCode = curl_errno($httph);//多维数组
    curl_close($httph);
    if (0 !== $errorCode) return false;//多维数组
    return $rst;
}

function getMillisecond() {
    list($s1, $s2) = explode(' ', microtime());
    return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
}